/*
 *  Author: Samuel Abels <spam debain org>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include "gui_ipv4analyzer.h"

//#define _DEBUG_


/******************************************************************************
 * Constructor/Destructor
 ******************************************************************************/
GUIIPv4Analyzer::GUIIPv4Analyzer()
{
#ifdef _DEBUG_
  printf("GUIIPv4Analyzer::GUIIPv4Analyzer(): Called.\n");
#endif
  HBox*        hbox  = NULL;
  Label*       label = NULL;
  SpinButton*  spin  = NULL;
  Entry*       entry = NULL;
  CheckButton* check = NULL;
  string       str;
  
  resize(17, 4);
  set_border_width(6);
  set_row_spacings(3);
  
  // ****************** "Input" section ******************.
  // Add all labels.
  label = new Label("", 0, 0.5);
  str = "<b>";
  str.append(_("Input"));
  str.append("</b>");
  label->set_markup(str);
  attach(*manage(label), 0, 4, 0, 1, FILL, FILL);
  
  label = new Label(_("IP Address:"), 0, 0.5);
  label->set_padding(12, 0);
  attach(*manage(label), 0, 1, 1, 2, FILL, FILL);
  
  label = new Label(_("Network Mask:"), 0, 0.5);
  label->set_padding(12, 0);
  attach(*manage(label), 0, 1, 2, 3, FILL, FILL);
  
  label = new Label(_("Prefix Length:"), 0, 0.5);
  label->set_padding(12, 0);
  attach(*manage(label), 0, 1, 3, 4, FILL, FILL);
  
  label = new Label("");
  attach(*manage(label), 0, 4, 4, 5, FILL, FILL);
  
  // Add all spin-buttons.
  spin = new SpinButton;
  spin->set_numeric(FALSE);
  spin->set_range(0, (double)pow((double)2, 32) - 1);
  spin->set_increments(1, 256);
  spin->set_wrap();
  widgets["ip"] = spin;
  attach(*manage(spin), 1, 4, 1, 2, FILL|EXPAND, FILL);
  spin->signal_input().connect(
        SigC::bind(SigC::slot(*this, &GUIIPv4Analyzer::map_ip_input), spin));
  spin->signal_output().connect(
        SigC::bind(SigC::slot(*this, &GUIIPv4Analyzer::map_ip_output), spin));
  spin->signal_value_changed().connect(
        SigC::slot(*this, &GUIIPv4Analyzer::on_ip_changed));
  
  spin = new SpinButton;
  spin->set_numeric(FALSE);
  spin->set_range(0, 32);
  spin->set_increments(1, 10);
  spin->set_wrap();
  widgets["mask"] = spin;
  attach(*manage(spin), 1, 4, 2, 3, FILL|EXPAND, FILL);
  spin->signal_input().connect(
        SigC::bind(SigC::slot(*this, &GUIIPv4Analyzer::map_mask_input), spin));
  spin->signal_output().connect(
        SigC::bind(SigC::slot(*this, &GUIIPv4Analyzer::map_mask_output), spin));
  spin->signal_value_changed().connect(
        SigC::slot(*this, &GUIIPv4Analyzer::on_mask_changed));
  
  spin = new SpinButton;
  spin->set_range(0, 32);
  spin->set_increments(1, 10);
  widgets["pfxlen"] = spin;
  attach(*manage(spin), 1, 4, 3, 4, FILL|EXPAND, FILL);
  spin->signal_value_changed().connect(
        SigC::slot(*this, &GUIIPv4Analyzer::on_pfxlen_changed));
  
  // ****************** "Output" section ******************.
  // Add the "Range" hbox.
  hbox = new HBox;
  attach(*manage(hbox), 2, 4, 6, 7, FILL|EXPAND, FILL);
  
  label = new Label("-", 0, 0.5);
  label->set_padding(12, 0);
  hbox->pack_start(*manage(label), FALSE, FALSE);
  
  entry = new Entry;
  widgets["out_rangeto"] = entry;
  hbox->pack_start(*manage(entry), TRUE, TRUE);
  
  // Add all labels.
  label = new Label("", 0, 0.5);
  str = "<b>";
  str.append(_("Output"));
  str.append("</b>");
  label->set_markup(str);
  attach(*manage(label), 0, 4, 5, 6, FILL, FILL);
  
  label = new Label(_("Address Range:"), 0, 0.5);
  label->set_padding(12, 0);
  attach(*manage(label), 0, 1, 6, 7, FILL, FILL);
  
  label = new Label(_("Number of Subnets:"), 0, 0.5);
  label->set_padding(12, 0);
  attach(*manage(label), 0, 1, 7, 8, FILL, FILL);
  
  label = new Label(_("Number of Hosts:"), 0, 0.5);
  label->set_padding(12, 0);
  attach(*manage(label), 0, 1, 8, 9, FILL, FILL);
  
  label = new Label(_("Including Net/Broadcast:"), 0, 0.5);
  label->set_padding(12, 0);
  attach(*manage(label), 2, 3, 8, 9, FILL, FILL);
  
  label = new Label(_("Network Address:"), 0, 0.5);
  label->set_padding(12, 0);
  attach(*manage(label), 0, 1, 9, 10, FILL, FILL);
  
  label = new Label(_("Broadcast Address:"), 0, 0.5);
  label->set_padding(12, 0);
  attach(*manage(label), 0, 1, 10, 11, FILL, FILL);
  
  label = new Label("");
  attach(*manage(label), 1, 4, 11, 12, FILL, FILL);
  
  // Add all entry boxes.
  entry = new Entry;
  widgets["out_rangefrom"] = entry;
  attach(*manage(entry), 1, 2, 6, 7, FILL|EXPAND, FILL);
  
  entry = new Entry;
  widgets["out_numsubnets"] = entry;
  attach(*manage(entry), 1, 4, 7, 8, FILL|EXPAND, FILL);
  
  entry = new Entry;
  widgets["out_numhosts"] = entry;
  attach(*manage(entry), 1, 2, 8, 9, FILL|EXPAND, FILL);
  
  entry = new Entry;
  widgets["out_numhosts_all"] = entry;
  attach(*manage(entry), 3, 4, 8, 9, FILL|EXPAND, FILL);
  
  entry = new Entry;
  widgets["out_network"] = entry;
  attach(*manage(entry), 1, 4, 9, 10, FILL|EXPAND, FILL);
  
  entry = new Entry;
  widgets["out_broadcast"] = entry;
  attach(*manage(entry), 1, 4, 10, 11, FILL|EXPAND, FILL);
  
  // ****************** "Output (Binary)" section ******************.
  // Add all labels.
  label = new Label("", 0, 0.5);
  str = "<b>";
  str.append(_("Output (Binary)"));
  str.append("</b>");
  label->set_markup(str);
  attach(*manage(label), 0, 4, 12, 13, FILL, FILL);
  
  label = new Label(_("IP Address:"), 0, 0.5);
  label->set_padding(12, 0);
  attach(*manage(label), 0, 1, 13, 14, FILL, FILL);
  
  label = new Label(_("Network Mask:"), 0, 0.5);
  label->set_padding(12, 0);
  attach(*manage(label), 0, 1, 14, 15, FILL, FILL);
  
  label = new Label(_("Network Address:"), 0, 0.5);
  label->set_padding(12, 0);
  attach(*manage(label), 0, 1, 15, 16, FILL, FILL);
  
  label = new Label(_("Broadcast Address:"), 0, 0.5);
  label->set_padding(12, 0);
  attach(*manage(label), 0, 1, 16, 17, FILL, FILL);
  
  // Add all entry boxes.
  entry = new Entry;
  widgets["bin_ip"] = entry;
  attach(*manage(entry), 1, 4, 13, 14, FILL|EXPAND, FILL);
  
  entry = new Entry;
  widgets["bin_mask"] = entry;
  attach(*manage(entry), 1, 4, 14, 15, FILL|EXPAND, FILL);
  
  entry = new Entry;
  widgets["bin_network"] = entry;
  attach(*manage(entry), 1, 4, 15, 16, FILL|EXPAND, FILL);
  
  entry = new Entry;
  widgets["bin_broadcast"] = entry;
  attach(*manage(entry), 1, 4, 16, 17, FILL|EXPAND, FILL);
}


GUIIPv4Analyzer::~GUIIPv4Analyzer()
{
#ifdef _DEBUG_
  printf("GUIIPv4Analyzer::~GUIIPv4Analyzer(): Called.\n");
#endif
}


/******************************************************************************
 * Public
 ******************************************************************************/
/* Switch event emissions off. */
void GUIIPv4Analyzer::lock_signals(void)
{
  lock_events = TRUE;
}


/* Switch event emissions on. */
void GUIIPv4Analyzer::unlock_signals(void)
{
  lock_events = FALSE;
}


/* Returns the value of the IP address field. */
unsigned int GUIIPv4Analyzer::get_ip(void)
{
#ifdef _DEBUG_
  printf("GUIIPv4Analyzer::get_ip(): Called.\n");
#endif
  SpinButton* spin = (SpinButton*)widgets["ip"];
  return (unsigned int)spin->get_value();
}


/* Sets the value of the IP address field. */
void GUIIPv4Analyzer::set_ip(unsigned int ip)
{
#ifdef _DEBUG_
  printf("GUIIPv4Analyzer::set_ip(): Called.\n");
#endif
  SpinButton* spin = (SpinButton*)widgets["ip"];
  spin->set_value((double)ip);
}


/* Sets the value of the IP netmask field. */
void GUIIPv4Analyzer::set_mask(unsigned int mask)
{
#ifdef _DEBUG_
  printf("GUIIPv4Analyzer::set_mask(): Called.\n");
#endif
  SpinButton*         spin   = (SpinButton*)widgets["mask"];
  unsigned short int  pfxlen = 0;
  ipv4_mask2pfxlen(mask, &pfxlen);
  spin->set_value((double)pfxlen);
}


/* Sets the value of the prefixlength field. */
void GUIIPv4Analyzer::set_pfxlen(unsigned short int pfxlen)
{
#ifdef _DEBUG_
  printf("GUIIPv4Analyzer::set_prefixlength(): Called.\n");
#endif
  SpinButton* spin = (SpinButton*)widgets["pfxlen"];
  spin->set_value((double)pfxlen);
}


/* Sets the value of the range fields. */
void GUIIPv4Analyzer::set_output_range(unsigned int from, unsigned int to)
{
#ifdef _DEBUG_
  printf("GUIIPv4Analyzer::set_output_range(): Called.\n");
#endif
  Entry* entryfrom = (Entry*)widgets["out_rangefrom"];
  Entry* entryto   = (Entry*)widgets["out_rangeto"];
  char text[16];
  if (ipv4_integer2ip(from, text) == 0)
    entryfrom->set_text(text);
  if (ipv4_integer2ip(to, text) == 0)
    entryto->set_text(text);
}


/* Sets the value of the "Output" -> "Number of Subnets" field. */
void GUIIPv4Analyzer::set_output_subnets(unsigned int num)
{
#ifdef _DEBUG_
  printf("GUIIPv4Analyzer::set_output_subnets(): Called.\n");
#endif
  Entry* entry = (Entry*)widgets["out_numsubnets"];
  char text[100];
  snprintf(text, 99, "%u", num);
  entry->set_text(text);
}


/* Sets the value of the "Output" -> "Number of Hosts" field. */
void GUIIPv4Analyzer::set_output_hosts(unsigned int num)
{
#ifdef _DEBUG_
  printf("GUIIPv4Analyzer::set_output_hosts(): Called.\n");
#endif
  Entry* entry = (Entry*)widgets["out_numhosts"];
  char text[100];
  snprintf(text, 99, "%u", num);
  entry->set_text(text);
}


/* Sets the value of the "Output" -> "Number of Hosts, including Net/BC"
 * field.
 */
void GUIIPv4Analyzer::set_output_hosts_all(unsigned int num)
{
#ifdef _DEBUG_
  printf("GUIIPv4Analyzer::set_output_hosts(): Called.\n");
#endif
  Entry* entry = (Entry*)widgets["out_numhosts_all"];
  char text[100];
  snprintf(text, 99, "%u", num);
  entry->set_text(text);
}


/* Sets the value of the "Output" -> "Network" field. */
void GUIIPv4Analyzer::set_output_network(unsigned int network)
{
#ifdef _DEBUG_
  printf("GUIIPv4Analyzer::set_output_network(): Called.\n");
#endif
  Entry* entry = (Entry*)widgets["out_network"];
  char network_text[16];
  if (ipv4_integer2ip(network, network_text) < 0)
    return;
  entry->set_text(network_text);
}


/* Sets the value of the "Output" -> "Network" field. */
void GUIIPv4Analyzer::set_output_broadcast(unsigned int broadcast)
{
#ifdef _DEBUG_
  printf("GUIIPv4Analyzer::set_output_broadcast(): Called.\n");
#endif
  Entry* entry = (Entry*)widgets["out_broadcast"];
  char broadcast_text[16];
  if (ipv4_integer2ip(broadcast, broadcast_text) < 0)
    return;
  entry->set_text(broadcast_text);
}


/* Sets the value of the "Output (Binary)" -> "IP" field. */
void GUIIPv4Analyzer::set_output_bin_ip(unsigned int ip)
{
#ifdef _DEBUG_
  printf("GUIIPv4Analyzer::set_output_bin_ip(): Called.\n");
#endif
  Entry* entry = (Entry*)widgets["bin_ip"];
  char binary[36];
  if (ipv4_integer2bin(ip, binary) == 0)
    entry->set_text(binary);
  else
    entry->set_text("");
}


/* Sets the value of the "Output (Binary)" -> "Netmask" field. */
void GUIIPv4Analyzer::set_output_bin_mask(unsigned int mask)
{
#ifdef _DEBUG_
  printf("GUIIPv4Analyzer::set_output_bin_mask(): Called.\n");
#endif
  Entry* entry = (Entry*)widgets["bin_mask"];
  char binary[36];
  if (ipv4_integer2bin(mask, binary) == 0)
    entry->set_text(binary);
  else
    entry->set_text("");
}


/* Sets the value of the "Output (Binary)" -> "Network Address" field. */
void GUIIPv4Analyzer::set_output_bin_network(unsigned int net)
{
#ifdef _DEBUG_
  printf("GUIIPv4Analyzer::set_output_bin_network(): Called.\n");
#endif
  Entry* entry = (Entry*)widgets["bin_network"];
  char binary[36];
  if (ipv4_integer2bin(net, binary) == 0)
    entry->set_text(binary);
  else
    entry->set_text("");
}


/* Sets the value of the "Output (Binary)" -> "Broadcast Address" field. */
void GUIIPv4Analyzer::set_output_bin_broadcast(unsigned int broadcast)
{
#ifdef _DEBUG_
  printf("GUIIPv4Analyzer::set_output_bin_broadcast(): Called.\n");
#endif
  Entry* entry = (Entry*)widgets["bin_broadcast"];
  char binary[36];
  if (ipv4_integer2bin(broadcast, binary) == 0)
    entry->set_text(binary);
  else
    entry->set_text("");
}


/******************************************************************************
 * Private
 ******************************************************************************/
int GUIIPv4Analyzer::map_ip_input(double* value, SpinButton* spin)
{
#ifdef _DEBUG_EXCESSIVE_
  printf("GUIIPv4Analyzer::map_ip_input(): Called.\n");
#endif
  string       ip     = spin->get_text();
  unsigned int ip_int = 0;
  if (ipv4_ip2integer(ip.c_str(), &ip_int) < 0)
    return 0;
#ifdef _DEBUG_EXCESSIVE_
  printf("GUIIPv4Analyzer::map_ip_input(): Value: %s=%i\n", ip.c_str(), ip_int);
#endif
  *value = (double)ip_int;
  return 1;
}


bool GUIIPv4Analyzer::map_ip_output(SpinButton* spin)
{
#ifdef _DEBUG_EXCESSIVE_
  printf("GUIIPv4Analyzer::map_ip_output(): Called.\n");
#endif
  char         ip[36] = "";
  unsigned int ip_int = (unsigned int)spin->get_adjustment()->get_value();
#ifdef _DEBUG_EXCESSIVE_
  printf("GUIIPv4Analyzer::map_ip_output(): Double: %d\n",
         spin->get_adjustment()->get_value());
#endif
  ipv4_integer2ip(ip_int, ip);
  spin->set_text(ip);
  return TRUE;
}


/* This inbound map is used to map IP mask spinbuttons to a mask. */
int GUIIPv4Analyzer::map_mask_input(double* value, SpinButton* spin)
{
#ifdef _DEBUG_EXCESSIVE_
  printf("GUIIPv4Analyzer::map_mask_input(): Called.\n");
#endif
  string             mask     = spin->get_text();
  unsigned int       mask_int = 0;
  unsigned short int pfxlen   = 0;
  if (ipv4_ip2integer(mask.c_str(), &mask_int) < 0)
    return 0;
  if (ipv4_mask2pfxlen(mask_int, &pfxlen) < 0)
    return 0;
#ifdef _DEBUG_EXCESSIVE_
  printf("GUIIPv4Analyzer::map_mask_input(): Value: %s, %i, %i\n",
         mask.c_str(),
         mask_int,
         pfxlen);
#endif
  *value = (double)pfxlen;
  return 1;
}


/* This outbound map is used to map IP mask spinbuttons to a mask. */
bool GUIIPv4Analyzer::map_mask_output(SpinButton* spin)
{
#ifdef _DEBUG_EXCESSIVE_
  printf("GUIIPv4Analyzer::map_mask_output(): Called.\n");
#endif
  char         mask[36] = "";
  unsigned int pfxlen   = (unsigned int)spin->get_adjustment()->get_value();
  unsigned int mask_int = 0;
  if (ipv4_pfxlen2mask((unsigned short int)pfxlen, &mask_int) < 0)
    return TRUE;
  ipv4_integer2ip(mask_int, mask);
#ifdef _DEBUG_EXCESSIVE_
  printf("GUIIPv4Analyzer::map_mask_output(): %i is %s\n", pfxlen, mask);
#endif
  spin->set_text(mask);
  return TRUE;
}


void GUIIPv4Analyzer::on_ip_changed(void)
{
#ifdef _DEBUG_
  printf("GUIIPv4Analyzer::on_ip_changed(): Called.\n");
#endif
  if (lock_events)
    return;
  SpinButton*         spin_ip   = (SpinButton*)widgets["ip"];
  SpinButton*         spin_mask = (SpinButton*)widgets["mask"];
  unsigned int        ip        = (unsigned int)spin_ip->get_value();
  unsigned short int  pfxlen    = (unsigned int)spin_mask->get_value();
  unsigned int        mask      = 0;
  ipv4_pfxlen2mask(pfxlen, &mask);
  signal_ip_changed.emit(ip, mask);
}


void GUIIPv4Analyzer::on_mask_changed(void)
{
#ifdef _DEBUG_
  printf("GUIIPv4Analyzer::on_mask_changed(): Called.\n");
#endif
  if (lock_events)
    return;
  SpinButton*         spin_ip   = (SpinButton*)widgets["ip"];
  SpinButton*         spin_mask = (SpinButton*)widgets["mask"];
  unsigned int        ip        = (unsigned int)spin_ip->get_value();
  unsigned short int  pfxlen    = (unsigned int)spin_mask->get_value();
  unsigned int        mask      = 0;
  ipv4_pfxlen2mask(pfxlen, &mask);
  signal_mask_changed.emit(ip, mask);
}


void GUIIPv4Analyzer::on_pfxlen_changed(void)
{
#ifdef _DEBUG_
  printf("GUIIPv4Analyzer::on_prefixlength_changed(): Called.\n");
#endif
  if (lock_events)
    return;
  SpinButton*        spin_ip     = (SpinButton*)widgets["ip"];
  SpinButton*        spin_pfxlen = (SpinButton*)widgets["pfxlen"];
  unsigned int       ip          = (unsigned int)spin_ip->get_value();
  unsigned short int pfxlen      = (unsigned short int)spin_pfxlen->get_value();
  signal_pfxlen_changed.emit(ip, pfxlen);
}
